﻿
//
//  Copyright (c) 2011 Extreme: Paweł Huryn (lead), Jakub Domański
//
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Castle.Core.Resource;
using Castle.Windsor;
using Castle.Windsor.Configuration.Interpreters;
using Extreme.SPFramework.Cache;

namespace Extreme.SPFramework.DependencyInjection
{   
    /// <summary>
    /// Service provider integrated with Castle Inversion of Control container
    /// </summary>
    public sealed class ServiceProvider
    {
        private static readonly IWindsorContainer Container = null;
        internal const decimal FrameworkVersion = 2;

        static ServiceProvider()
        {
            Container = new WindsorContainer(new XmlInterpreter(new ConfigResource("castle")));

            // TODO: temporary hack, assembly not loaded
            AddComponent(typeof (SimpleCache), typeof (ICache), LifestyleType.Singleton);

            var allAssembliesList = new List<Assembly>(AppDomain.CurrentDomain.GetAssemblies());
            foreach (var logicAssembly in allAssembliesList)
            {
                if (logicAssembly.GetCustomAttributes(false).Count(
                    item => item is ServiceContainer && 
                    ((ServiceContainer)item).FrameworkVersion == FrameworkVersion) == 0)
                    continue;

                foreach (var type in logicAssembly.GetTypes())
                {
                    var allAttributes = type.GetCustomAttributes(false).Where(item => item is ServiceAttribute).ToList();
                    if (allAttributes.Count == 1 && ((ServiceAttribute)allAttributes[0]).Interface == null)
                    {
                        // register all interfaces
                        var allInterfaces = type.GetInterfaces().ToList();
                        foreach (var interfaceType in allInterfaces)
                        {
                            AddComponent(type, interfaceType, ((ServiceAttribute)allAttributes[0]).Lifestyle);
                        }
                    }
                    else
                    {
                        foreach (var attribute in allAttributes)
                        {
                            var serviceAttribute = (ServiceAttribute)attribute;
                            if(serviceAttribute.Interface != null)
                                AddComponent(type, serviceAttribute.Interface, serviceAttribute.Lifestyle);
                        }
                    }
                }
            }
        }

        /// <summary>
        /// Gets instance of specified type
        /// </summary>
        /// <typeparam name="T">Type of instance</typeparam>
        /// <returns>Object that is T</returns>
        public static T GetInstance<T>()
        {
            return Container.Resolve<T>();
        }

        /// <summary>
        /// Gets all instances of specified type
        /// </summary>
        public static List<T> GetAllInstances<T>()
        {
            return Container.ResolveAll<T>().ToList();
        }

        private static void AddComponent(Type type, Type interfaceType, LifestyleType? lifestyle)
        {
            var key = type.FullName + interfaceType.FullName;

            if (!lifestyle.HasValue)
            {
                Container.AddComponent(key, interfaceType, type);
            }
            else
            {
                Container.AddComponentLifeStyle(key, interfaceType, type, (Castle.Core.LifestyleType)lifestyle.Value);
            }
        }
    }
}
